//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "functional.h"

////////////////////////////////////////
// Function adaptors (depricated)
//
// This file implements the c++03
// standard function adaptor classes.
////////////////////////////////////////

FC_NAMESPACE_BEGIN


// unary_negate

template <class Predicate>
class unary_negate : public unary_function<typename Predicate::argument_type, bool>
{
public:
	explicit unary_negate(const Predicate& p) : predicate(p) {}
	bool operator()( const typename Predicate::argument_type& a ) const { return !predicate(a); }
protected:
	Predicate predicate;
};


// binary_negate

template <class Predicate>
class binary_negate : public binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_type, bool>
{
public:
	explicit binary_negate(const Predicate& p) : predicate(p) { }
	bool operator()( const typename Predicate::first_argument_type& a, const typename Predicate::second_argument_type& b ) const
	{ return !predicate(a, b); }
protected:
	Predicate predicate;
};


// binder1st

template <class Operation>
class binder1st : public unary_function<typename Operation::second_argument_type, typename Operation::result_type>
{
public:
	binder1st( const Operation& x, const typename Operation::first_argument_type& y ) : value(y), op(x) {}
	typename Operation::result_type operator()( const typename Operation::second_argument_type& x ) const { return op(value, x); }
	typename Operation::result_type operator()( typename Operation::second_argument_type& x ) const { return op(value, x); }
protected:
	typename Operation::first_argument_type value;
	Operation op;
};


// binder2nd

template <class Operation>
class binder2nd : public unary_function<typename Operation::first_argument_type, typename Operation::result_type>
{
public:
	binder2nd( const Operation& x, const typename Operation::second_argument_type& y ) : op(x), value(y) { }
	typename Operation::result_type operator()( const typename Operation::first_argument_type& x ) const { return op(x, value); }
	typename Operation::result_type operator()( typename Operation::first_argument_type& x ) const { return op(x, value); }
protected:
	Operation op;
	typename Operation::second_argument_type value;
};


// pointer_to_unary_function

template <class Argument, class Result>
class pointer_to_unary_function : public unary_function<Argument, Result>
{
public:
	pointer_to_unary_function() {}
	explicit pointer_to_unary_function( Result (*f)(Argument) ) : pFunc(f) {}
	Result operator()(Argument x) const { return pFunc(x); }
protected:
	Result (*pFunc)(Argument);
};


// pointer_to_binary_function

template <class Argument1, class Argument2, class Result>
class pointer_to_binary_function : public binary_function<Argument1, Argument2, Result>
{
public:
	pointer_to_binary_function() {}
	explicit pointer_to_binary_function( Result (*f)(Argument1, Argument2) ) : pFunc(f) {}
	Result operator()(Argument1 x, Argument2 y) const { return pFunc(x, y); }
protected:
	Result (*pFunc)(Argument1, Argument2);
};



template <class Predicate> inline
	unary_negate<Predicate> not1(const Predicate& predicate)
	{
		return unary_negate<Predicate>(predicate);
	}

template <class Predicate> inline
	binary_negate<Predicate> not2(const Predicate& predicate)
	{
		return binary_negate<Predicate>(predicate);
	}

template <class Operation, class T> inline
	binder1st<Operation> bind1st( const Operation& op, const T& x )
	{
		return binder1st<Operation>(op, typename Operation::first_argument_type(x));
	}

template <class Operation, class T> inline
	binder2nd<Operation> bind2nd( const Operation& op, const T& x )
	{
		return binder2nd<Operation>(op, typename Operation::second_argument_type(x));
	}

template <class Argument, class Result> inline
	pointer_to_unary_function<Argument, Result> ptr_fun( Result (*f)(Argument) )
	{
		return pointer_to_unary_function<Argument, Result>(f);
	}

template <class Argument1, class Argument2, class Result> inline
	pointer_to_binary_function<Argument1, Argument2, Result> ptr_fun( Result (*f)(Argument1, Argument2) )
	{
		return pointer_to_binary_function<Argument1, Argument2, Result>(f);
	}



// memory funcion adaptors

template <class Result, class T>
class mem_fun_t : public unary_function<T*, Result>
{
public:
	typedef Result (T::*pMemberFunction)();
	explicit mem_fun_t( pMemberFunction f ) : pFunc(f) {}
	Result operator()( T* p ) const { return (p->*pFunc)(); }
protected:
	pMemberFunction pFunc;
};


template <class Result, class T, class Argument>
class mem_fun1_t : public binary_function<T*, Argument, Result>
{
public:
	typedef Result (T::*pMemberFunction)(Argument);
	explicit mem_fun1_t( pMemberFunction f ) : pFunc(f) {}
	Result operator()( T* p, Argument arg ) const { return (p->*pFunc)(arg); }
protected:
	pMemberFunction pFunc;
};


template <class Result, class T>
class mem_fun_ref_t : public unary_function<T, Result>
{
public:
	typedef Result (T::*pMemberFunction)();
	explicit mem_fun_ref_t( pMemberFunction f ) : pFunc(f) {}
	Result operator()( T& t ) const { return (t.*pFunc)(); }
protected:
	pMemberFunction pFunc;
};


template <class Result, class T, class Argument>
class mem_fun1_ref_t : public binary_function<T, Argument, Result>
{
public:
	typedef Result (T::*pMemberFunction)(Argument);
	explicit mem_fun1_ref_t( pMemberFunction f ) : pFunc(f) {}
	Result operator()( T& t, Argument arg ) const { return (t.*pFunc)(arg); }
protected:
	pMemberFunction pFunc;
};


template <class Result, class T>
class const_mem_fun_t : public unary_function<const T*, Result>
{
public:
	typedef Result (T::*pMemberFunction)() const;
	explicit const_mem_fun_t( pMemberFunction f ) : pFunc(f) {}
	Result operator()( const T* p ) const { return (p->*pFunc)(); }
protected:
	pMemberFunction pFunc;
};


template <class Result, class T, class Argument>
class const_mem_fun1_t : public binary_function<const T*, Argument, Result>
{
public:
	typedef Result (T::*pMemberFunction)(Argument) const;
	explicit const_mem_fun1_t( pMemberFunction f ) : pFunc(f) {}
	Result operator()( const T* p, Argument arg ) const { return (p->*pFunc)(arg); }
protected:
	pMemberFunction pFunc;
};


template <class Result, class T>
class const_mem_fun_ref_t : public unary_function<T, Result>
{
public:
	typedef Result (T::*pMemberFunction)() const;
	explicit const_mem_fun_ref_t( pMemberFunction f ) : pFunc(f) {}
	Result operator()( const T& t ) const { return (t.*pFunc)(); }
protected:
	pMemberFunction pFunc;
};


template <class Result, class T, class Argument>
class const_mem_fun1_ref_t : public binary_function<T, Argument, Result>
{
public:
	typedef Result (T::*pMemberFunction)(Argument) const;
	explicit const_mem_fun1_ref_t( pMemberFunction f ) : pFunc(f) {}
	Result operator()( const T& t, Argument arg ) const { return (t.*pFunc)(arg); }
protected:
	pMemberFunction pFunc;
};


// mem_fun

template <class Result, class T> inline
	mem_fun_t<Result, T> mem_fun( Result (T::*pMemberFunction)() )
	{
		return mem_fun_t<Result, T>(pMemberFunction);
	}

template <class Result, class T, class Argument> inline
	mem_fun1_t<Result, T, Argument> mem_fun( Result (T::*pMemberFunction)(Argument) )
	{
		return mem_fun1_t<Result, T, Argument>(pMemberFunction);
	}

template <class Result, class T> inline
	const_mem_fun_t<Result, T> mem_fun( Result (T::*pMemberFunction)() const )
	{
		return const_mem_fun_t<Result, T>(pMemberFunction);
	}

template <class Result, class T, class Argument> inline
	const_mem_fun1_t<Result, T, Argument> mem_fun( Result (T::*pMemberFunction)(Argument) const )
	{
		return const_mem_fun1_t<Result, T, Argument>(pMemberFunction);
	}

// mem_fun_ref

template <class Result, class T> inline
	mem_fun_ref_t<Result, T> mem_fun_ref( Result (T::*pMemberFunction)() )
	{
		return mem_fun_ref_t<Result, T>(pMemberFunction);
	}

template <class Result, class T, class Argument> inline
	mem_fun1_ref_t<Result, T, Argument> mem_fun_ref( Result (T::*pMemberFunction)(Argument) )
	{
		return mem_fun1_ref_t<Result, T, Argument>(pMemberFunction);
	}

template <class Result, class T> inline
	const_mem_fun_ref_t<Result, T> mem_fun_ref( Result (T::*pMemberFunction)() const )
	{
		return const_mem_fun_ref_t<Result, T>(pMemberFunction);
	}

template <class Result, class T, class Argument> inline
	const_mem_fun1_ref_t<Result, T, Argument> mem_fun_ref( Result (T::*pMemberFunction)(Argument) const )
	{
		return const_mem_fun1_ref_t<Result, T, Argument>(pMemberFunction);
	}




FC_NAMESPACE_END
